<!--
  文件描述：流程图
-->
<template>
  <div class="box" @mousedown.prevent="startDrag" @wheel.prevent="handleWheel">
    <div class="background">
      <div class="scale-box">
        <add-button-icon icon="Minus" borderRadius="5px" backgroundColor="#fff" color="rgb(118 118 118)"
          @click="changeScale('min')" />
        <div class="scale-text">{{ realTimeScale }}</div>
        <add-button-icon borderRadius="5px" backgroundColor="#fff" color="rgb(118 118 118)"
          @click="changeScale('add')" />
        <add-button-icon icon="Refresh" borderRadius="5px" backgroundColor="#fff" color="rgb(118 118 118)"
          @click="changeScale('return')" style="margin-left: 5px" />
      </div>
      <div class="big-bx" :style="realTimeStyle" @touchstart="handleTouchStart">
        <process-page-item :process-data="getAfterDealData" :disabled="disabled" />
        <!--  流程结束    -->
        <div class="end-node">
          <div class="end-node-circle"></div>
          <div class="end-node-text">流程结束</div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup name="process">
import { computed, onMounted, onUnmounted, provide, ref, watch } from "vue";
import processPageItem from '@/view/workflow/config/components/processPageItem.vue'
import { ElMessage } from "element-plus";
import addButtonIcon from '@/components/add-button-icon.vue'

const props = defineProps({
  processData: {
    type: Object,
    default: {}
  },
  disabled: {
    type: Boolean,
    default: false
  }
})
// 位移，缩放状态
const state = ref({
  isDragging: false,
  scale: 1,
  scaleFactor: 10,
  minScale: 0.5,
  maxScale: 5,
  startX: 0,
  startY: 0,
  translateX: 0,
  translateY: 0,
  initTranslateX: 0,
  initTranslateY: 0,

  // 触屏
  initialDistance: 0,
  initialScale: 1,
  centerX: 0,
  centerY: 0
})

watch(() => props.processData,
  (newProcessData) => {
    getAfterDealData.value = newProcessData
  }
)

// 流程图添加数据
const processAddData = computed(() => (nodeType) => ({
  nodeType,
  nodeId: (Math.floor(Math.random() * (99999999 - 10000000 + 1)) + 10000000) + '',
  nodeNm: nodeType === '0' ? '发起人' : nodeType === '1' ? '审批人' : '审批条件',
  childNode: null,
  multiType: nodeType === '1' ? '0' : null,
  approvalType: '0',
  assigneeType: nodeType === '0' ? 'n' : nodeType === '1' ? '5' : null,
  conditionNodes: [],
  backStrategy: nodeType === '1' ? '0' : null,
  nodeConditions: [],
  operationButton: nodeType === '1' ? '0,1,2,3,4' : null
}))

// 实时计算流程图位置
const realTimeStyle = computed(() => {
  return {
    cursor: state.value.isDragging ? 'grabbing' : 'grab',
    transform: `translate(${state.value.translateX}px, ${state.value.translateY}px) scale(${state.value.scale})`,
    // transition: 'transform 0.3s ease',
  }
})

// 实时计算流程图缩放
const realTimeScale = computed(() => {
  return (state.value.scale * 100).toFixed(0) + '%'
})

const getAfterDealData = ref({})

const init = () => {
  getAfterDealData.value = {
    ...(props.processData ? props.processData : processAddData.value('0'))
  }
  // console.log(getAfterDealData.value, '---当前传入组件的流程图数据---')
}

// 添加数据
const addData = (params) => {
  // console.log(params, '触发祖组件')
  if (!params.nodeId) return
  const cur = getNeedChangeNode(params.nodeId, getAfterDealData.value)
  // console.log(cur, '--当前选择--')
  if (!cur) return ElMessage.error('暂未查询到数据！')
  addProcess(params.type, cur)
  // console.log(getAfterDealData.value, '--操作之后的流程图数据---')
};

// 递归 根据nodeId 查找对应的节点
// nodeType： 0、发起人 1、审批节点 2、条件 3、具体条件
const getNeedChangeNode = (nodeId, val) => {
  // console.log(nodeId, val.nodeId, '对应节点---被查找的数据-')
  let back = null
  if (val.nodeId === nodeId) {
    return val
  } else if (['0', '1', '3'].includes(val.nodeType) && val.childNode) {
    back = getNeedChangeNode(nodeId, val.childNode)
  } else if (val.nodeType === '2' && !back) { // 条件节点
    if ((val.conditionNodes || []).length) {
      val.conditionNodes.forEach(item => {
        if (!back) {
          back = getNeedChangeNode(nodeId, item)
        }
      })
    }
    if (val.childNode && !back) {
      back = getNeedChangeNode(nodeId, val.childNode)
    }
  }
  return back
}

// 递归 根据nodeId 查询父节点
const getParentsNode = (nodeId, val) => {
  console.log(nodeId, val.childNode?.nodeId, '父节点---被查询节点---')
  let back = null
  if (val.childNode?.nodeId === nodeId) {
    return val
  } else if (['0', '1', '3'].includes(val.nodeType) && val.childNode) {
    back = getParentsNode(nodeId, val.childNode)
  } else if (['2'].includes(val.nodeType) && !back) {
    if ((val.conditionNodes || []).length && !back) {
      val.conditionNodes.forEach(item => {
        if (!back) {
          if (item.nodeId === nodeId) {
            back = val
          } else {
            back = getParentsNode(nodeId, item)
          }
        }
      })
    }
    if (val.childNode && !back) {
      back = getParentsNode(nodeId, val.childNode)
    }
  }
  return back
}

// 添加审批人、条件
const addProcess = (type, choose) => {
  let add = null
  if (type === '1') { // 添加审批人
    add = processAddData.value("1")
  } else if (type === '2') { // 添加条件
    add = {
      ...processAddData.value("2"),
      conditionNodes: [
        {
          nodeId: Math.random() + '',
          ...processAddData.value('3')
        }, {
          nodeId: Math.random() + '',
          ...processAddData.value('3')
        }
      ]
    }
  } else if (type === '3') { // 添加具体条件
    add = processAddData.value('3')
  }

  if (['2'].includes(choose.nodeType) && type === '3') {
    choose.conditionNodes.push(JSON.parse(JSON.stringify(add)))
  } else {
    // 处理思路：1.先保存当前选择项的下一层级；2.添加中间节点；
    // 3.再将1中保存的下一层级添加在 新增加的中间节点之后
    const haveChildNode = choose.childNode ? JSON.parse(JSON.stringify(choose.childNode)) : null
    choose.childNode = JSON.parse(JSON.stringify(add))
    choose.childNode.childNode = haveChildNode
  }
}

// 删除数据
const deleData = (params) => {
  // console.log(params, '---删除数据--')
  if (!params.nodeId) return
  const cur = getNeedChangeNode(params.nodeId, getAfterDealData.value)
  // console.log(cur, '--当前选择--')
  // if (!cur) return ElMessage.error('暂未查询到数据！')
  const parentsNode = getParentsNode(params.nodeId, getAfterDealData.value)
  // console.log(parentsNode, '---当前父节点----')

  if (['1'].includes(cur.nodeType)) {
    // 删除 审批人
    // 思路：1.将要被删除节点的子节点保存；2.直接赋值为父节点的新子节点
    parentsNode.childNode = cur.childNode ? JSON.parse(JSON.stringify(cur.childNode)) : null

  } else if (['3'].includes(cur.nodeType)) {
    // 删除具体条件
    // 思路： 1.父节点中包含 2 条子节点以上的，则删除 当前节点;
    // 2.父节点只包含 2 条子节点的，则将父节点整个删除

    if (parentsNode.conditionNodes?.length > 2) {
      const index = parentsNode.conditionNodes.findIndex(item => item.nodeId === cur.nodeId)
      if (index >= 0) {
        parentsNode.conditionNodes.splice(index, 1)
      }
    } else {
      // 1、先查询父节点的父节点;
      const parentsFather = getParentsNode(parentsNode.nodeId, getAfterDealData.value)
      // console.log(parentsFather, '---当前节点父节点的父节点----')

      parentsFather.childNode = JSON.parse(JSON.stringify(parentsNode.childNode))
    }
  }
}


// 流程图-缩放
const changeScale = (type) => {
  if (type === 'min') {
    if (state.value.scale <= state.value.minScale) return
    state.value.scale = getScale(-state.value.scaleFactor)
    // state.value.scale -= 0.1
  } else if (type === 'return') {
    state.value.scale = 1
    state.value.translateX = 0
    state.value.translateY = 0
  } else {
    if (state.value.scale >= state.value.maxScale) return
    state.value.scale = getScale(state.value.scaleFactor)
    // state.value.scale += 0.1
  }
  // console.log(state.value.scale, '----')
}

// 缩放的大小
const getScale = (factor) => {
  return parseFloat((((state.value.scale * 100) + factor) / 100) + '').toFixed(2)
}

// 流程图-鼠标-拖拽启动
const startDrag = (e) => {
  state.value.isDragging = true
  state.value.startX = e.clientX
  state.value.startY = e.clientY
  state.value.initTranslateX = state.value.translateX
  state.value.initTranslateY = state.value.translateY
  window.addEventListener('mousemove', handleDrag)
  window.addEventListener('mouseup', stopDrag)

}

// 流程图-鼠标-拖拽处理
const handleDrag = (e) => {
  if (!state.value.isDragging) return
  // console.log('----拖拽中---', e.clientX, '--偏移量：--', e.clientX - state.value.startX, '---translateX--', state.value.initTranslateX + (e.clientX - state.value.startX))
  state.value.translateX = state.value.initTranslateX + (e.clientX - state.value.startX)
  state.value.translateY = state.value.initTranslateY + (e.clientY - state.value.startY)
}

// 流程图-鼠标-停止拖拽
const stopDrag = () => {
  state.value.isDragging = false
  clearupEvents()
}

// 清除事件监听
const clearupEvents = () => {
  window.removeEventListener('mousemove', handleDrag)
  window.removeEventListener('mouseup', stopDrag)

  window.removeEventListener('touchmove', handleTouchMove)
  window.removeEventListener('touchend', stopDrag)
  window.removeEventListener('touchcancel', stopDrag)
}


// 流程图-鼠标滚动-缩放、位移
const handleWheel = (e) => {
  const delta = e.deltaY > 0 ? -1 : 1
  const newScale = Math.min(state.value.maxScale, Math.max(state.value.minScale, getScale(delta)))

  const x = e.clientX - state.value.translateX
  const y = e.clientY - state.value.translateY

  state.value.translateX -= x * (newScale / state.value.scale - 1)
  state.value.translateY -= y * (newScale / state.value.scale - 1)
  state.value.scale = newScale
}

// 流程图-触屏-位移
const handleTouchStart = (event) => {
  state.value.isDragging = true
  state.value.initTranslateX = state.value.translateX
  state.value.initTranslateY = state.value.translateY
  if (event.touches.length === 2) {
    // 双指缩放初始化:ml-citation{ref="3,8" data="citationList"}
    const touch1 = event.touches[0]
    const touch2 = event.touches[1]
    state.value.initialDistance = getTouchDistance(touch1, touch2)
    state.value.initialScale = state.value.scale
    state.value.centerX = getTouchCenter(touch1, touch2).x
    state.value.centerY = getTouchCenter(touch1, touch2).y
  } else if (event.touches.length === 1) {
    // 单指移动初始化:ml-citation{ref="1,3" data="citationList"}
    const touch = event.touches[0]
    state.value.startX = touch.clientX
    state.value.startY = touch.clientY
  }
  window.addEventListener('touchmove', handleTouchMove)
  window.addEventListener('touchend', stopDrag)
  window.addEventListener('touchcancel', stopDrag)
};

const handleTouchMove = (event) => {
  event.preventDefault();
  if (event.touches.length === 2) {
    // 处理双指缩放:ml-citation{ref="3,7" data="citationList"}
    const touch1 = event.touches[0]
    const touch2 = event.touches[1]
    const currentDistance = getTouchDistance(touch1, touch2)
    const newScale = (currentDistance / state.value.initialDistance) * state.value.initialScale

    // 保持缩放中心点:ml-citation{ref="7,8" data="citationList"}
    const currentCenter = getTouchCenter(touch1, touch2);
    state.value.translateX = currentCenter.x - (state.value.centerX - state.value.initTranslateX) * (newScale / state.value.initialScale);
    state.value.translateY = currentCenter.y - (state.value.centerY - state.value.initTranslateY) * (newScale / state.value.initialScale);

    state.value.scale = Math.min(state.value.maxScale, Math.max(state.value.minScale, newScale))
  } else if (event.touches.length === 1) {
    // 处理单指移动:ml-citation{ref="1,3" data="citationList"}
    const touch = event.touches[0]
    state.value.translateX = state.value.initTranslateX + touch.clientX - state.value.startX
    state.value.translateY = state.value.initTranslateY + touch.clientY - state.value.startY
  }

};

// 工具函数
const getTouchDistance = (t1, t2) => {
  return Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY);
};

const getTouchCenter = (t1, t2) => {
  return {
    x: (t1.clientX + t2.clientX) / 2,
    y: (t1.clientY + t2.clientY) / 2
  };
};



onUnmounted(() => {
  clearupEvents()
  // window.removeEventListener('mousedown', startDrag)
  // window.removeEventListener('wheel', handleWheel)
})

onMounted(() => {
  // 禁止复制
  document.onselectstart = () => {
    return false
  }
  init()
  // window.addEventListener('mousedown', startDrag)
  // window.addEventListener('wheel', handleWheel)
})

// 给子组件提供更改数据方式
provide('addData', addData)
provide('deleData', deleData)

// 父组件可获取值
defineExpose({
  getAfterDealData
})

</script>
<style scoped lang="less">
@import '@/view/workflow/config/components/index.less';

.box {
  border-radius: 10px;
  background-color: var(--table-title-color);
  padding: 10px;
  touch-action: none;
}

.background {
  height: 65vh;
  background-color: var(--table-title-color);
  position: relative;
  overflow: hidden;
}

.scale-box {
  display: flex;
  justify-content: end;
  align-items: center;
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 10;
}

.scale-text {
  width: 70px;
  text-align: center;
}
</style>